home *** CD-ROM | disk | FTP | other *** search
- From: Tom Truscott <decvax!mcnc!rti-sel!trt>
- Subject: wm - a window manager (part 3 of 4)
- Newsgroups: mod.sources
- Approved: john@genrad.UUCP
-
- Mod.sources: Volume 2, Issue 33
- Submitted by: Tom Truscott <decvax!mcnc!rti-sel!trt>
-
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # misc.c
- # save.c
- # shell.c
- # vterm.c
- # wlist.c
- # wm.c
- # This archive created: Fri Aug 2 13:13:19 1985
- export PATH; PATH=/bin:$PATH
- echo shar: extracting "'misc.c'" '(11326 characters)'
- if test -f 'misc.c'
- then
- echo shar: will not over-write existing file "'misc.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'misc.c'
- /*
- *************
- * DISTRIBUTION NOTICE July 30 1985
- * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
- * Research Triangle Institute, (919) 541-7005.
- * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
- * Naval Research Laboratory, (202) 767-3365.
- * No claims or warranties of any sort are made for this distribution.
- * General permission is granted to copy, but not for profit,
- * any of this distribution, provided that this notice
- * is always included in the copies.
- *************
- */
- /*
- * Miscellaneous routines for the window manager.
- */
- #include "wm.h"
-
- /*
- * Get next unused slot in window structure array.
- * Returns slot number, or -1 if no slot available.
- */
- int GetSlot()
- {
- register int w;
-
- for (w = MINWINDOW; w < MAXWINDOWS; w++)
- if (!(win[w].flags&INUSE))
- return(w);
-
- return(-1);
- }
-
- /*
- * Prompt user for a window name.
- */
- askwindow()
- {
- register int w, c;
-
-
- w = -1;
- c = tty_getch();
-
- if (c == CANCEL1 || c == CANCEL2)
- showmsg("Canceled.");
-
- else if (c == 'l')
- {
- if (iswindow(lastw))
- w = lastw;
- else
- showmsg("No last window.");
- }
-
- else
- {
- if ( ! isdigit(c))
- showmsg("Indicate window by number, or 'l' for last window.");
- else if ( ! iswindow(ctoi(c)))
- showmsg("Window #%d does not exist.", ctoi(c));
- else
- w = ctoi(c);
- }
-
- return(w);
- }
-
- /*
- * Reshape window.
- * Returns 0 on normal completion, -1 otherwise.
- * On abnormal completion (e.g. the user cancels)
- * if this is a new window (flag) it will be deleted,
- * otherwise it is restored to its original state..
- * In the impossible(?) event that the window cannot
- * be restored it is deleted, sorry.
- */
- getbounds(w, flag)
- register int w;
- int flag;
- {
- register WINDOW *wp, *twp;
-
- /* Unpleasant hack: we save the real window contents while
- * a stunt double gets moved about.
- */
- wp = win[w].wptr;
- if ((win[w].wptr=newwin(wlines(wp),wcols(wp),wbegy(wp),wbegx(wp)))==NULL) {
- win[w].wptr = wp;
- showmsg("Cannot allocate temporary window!");
- return(-1);
- }
-
- showmsg("Move cursor to lower left corner (using hjkl), then type x.");
- if (getpos(w, 0) != 0) {
- delwin(win[w].wptr);
- win[w].wptr = wp;
- if (flag||NewWindow(w, wlines(wp), wcols(wp), wbegy(wp), wbegx(wp))) {
- WListDelete(w);
- FreeWindow(w);
- }
- RedrawScreen();
- return(-1);
- }
-
- showmsg("Now move cursor to upper right corner, then type x.");
- if (getpos(w, 1) != 0) {
- delwin(win[w].wptr);
- win[w].wptr = wp;
- if (flag||NewWindow(w, wlines(wp), wcols(wp), wbegy(wp), wbegx(wp))) {
- WListDelete(w);
- FreeWindow(w);
- }
- RedrawScreen();
- return(-1);
- }
-
- twp = win[w].wptr;
- win[w].wptr = wp;
- if (NewWindow(w, wlines(twp), wcols(twp), wbegy(twp), wbegx(twp))) {
- delwin(twp);
- WListDelete(w);
- FreeWindow(w);
- RedrawScreen();
- return(-1);
- }
- delwin(twp);
- RedrawScreen();
- return(0);
- }
-
- /*
- * Key definitions used only by routine getpos
- * These keys are used only for entering position of new window
- */
- # define RIGHTCHAR 'l'
- # define UPCHAR 'k'
- # define LEFTCHAR 'h'
- # define DOWNCHAR 'j'
- # define BIGRIGHTCHAR 'L' /* jump */
- # define BIGUPCHAR 'K' /* one-fifth of the */
- # define BIGLEFTCHAR 'H' /* way across */
- # define BIGDOWNCHAR 'J' /* the screen */
- # define EXECCHAR 'x'
-
- /*
- * move window on screen using UPCHAR, etc.
- * If flag is 0, then window is dragged at lower left.
- * If flag is non-zero, then window is re-sized at upper right.
- * Does not permit bottom (y=LINES-1) line, as it is saved for messages
- * Returns 0 on normal completion, -1 if user cancels.
- */
- getpos(w, flag)
-
- int w, flag;
- {
- register WINDOW *wp;
- register int x0, y0;
- register int c;
- int bigvert, bighoriz;
- int lines, cols; /* original size of window */
- int aline, acol; /* 'anchored' corner of window */
- int top, bot, left, right;
-
- bigvert=LINES/5+1;
- bighoriz=COLS/5+1;
-
- wp = win[w].wptr;
- lines = wlines(wp);
- cols = wcols(wp);
- y0 = wbegy(wp)+lines-1;
- x0 = wbegx(wp);
- if (flag) { /* re-size box */
- aline = y0;
- acol = x0;
- y0 = wbegy(wp);
- x0 = wbegx(wp)+cols-1;
- }
- RedrawScreen();
- (void) movecursor(y0,x0);
- (void) fflush(stdout);
-
- while ((c = tty_getch()) != EXECCHAR)
- {
- switch (c)
- {
- case KEY_HOME: x0=y0=0; break;
- case KEY_RIGHT:
- case RIGHTCHAR: x0 += 1; break;
- case KEY_UP:
- case UPCHAR: y0 -= 1; break;
- case KEY_BACKSPACE:
- case KEY_LEFT:
- case LEFTCHAR: x0 -= 1; break;
- case KEY_DOWN:
- case DOWNCHAR: y0 += 1; break;
- case BIGRIGHTCHAR: x0 += bighoriz; break;
- case BIGUPCHAR: y0 -= bigvert; break;
- case BIGLEFTCHAR: x0 -= bighoriz; break;
- case BIGDOWNCHAR: y0 += bigvert; break;
- default:
- if (c == CANCEL1 || c == CANCEL2)
- {
- showmsg("Canceled.");
- return(-1);
- }
- else
- flash();
- break;
- }
- x0 = MAX(x0, 0); x0 = MIN(x0, COLS-1);
- y0 = MAX(y0, 0); y0 = MIN(y0, LINES-2);
-
- if (!flag) { /* drag box */
- bot = y0;
- left = x0;
- top = y0+1 - lines; top = MAX(top, 0);
- right = x0+cols-1; right = MIN(right, COLS-1);
- } else { /* re-size box */
- bot = MAX(y0, aline);
- left = MIN(x0, acol);
- top = MIN(y0, aline);
- right = MAX(x0, acol);
- }
- if (NewWindow(w, bot+1-top, right+1-left, top, left))
- return(-1);
- wp = win[w].wptr;
- if (!tty_inputpending()) {
- RedrawScreen();
- (void) movecursor(y0,x0);
- (void) fflush(stdout);
- }
- }
-
- return(0);
- }
-
- /*
- * If c is a control character, make it printable,
- * e.g. '\007' ==> '^G'.
- */
- char *
- mkprint(c)
-
- register int c;
- {
- static char pbuf[3];
-
-
- pbuf[0] = (c>='\040' && c<'\177' ? c : '^');
- pbuf[1] = (c<'\040' ? c+0100 : c<'\177' ? '\0' : '?');
- pbuf[2] = '\0';
-
- return(pbuf);
- }
-
- /*
- * Send a setenv command for wmvirt terminal to shell in window w.
- * Note: this is a sad kludge. If fails if 'vi' or anything
- * other than the wm-activated shell is active in the window.
- * It is rumored that 4.3 BSD supports an ioctl to change
- * the window size (and corresponding signals that are understood
- * by screen managers). That will provide a better alternative.
- * Note: the setenv hack will still be needed for sessions
- * on remote machines via "tip".
- * Rlogin should (in 4.2 BSD does not) pass along TERMCAP
- * in addition to TERM.
- *
- * mode 0 -- disconnect termcap (unlink sneakytermcap file)
- * mode 1 -- set termcap, attempting sneaky termcap method first.
- * mode 2 -- set termcap, storing termcap string in environment
- * mode 3 -- set termcap by writing a shell command to the window
- */
- XSetTerm(w, mode)
-
- register int w, mode;
- {
- register int i, fd;
- register char *s, *lasts;
-
- #ifdef SNEAKYTERMCAP
- if (mode < 3) {
- /*
- * Use of /tmp to hold the termcap files is a security hole
- * on most UNIX systems. Safer, but more trouble,
- * would be to put these files in a directory in the
- * users home directory.
- */
- char termfile[100];
- int oldmask;
- (void) sprintf(termfile, "/tmp/WM.%d.%d",
- (mode==1? getppid(): getpid()), w);
- (void) unlink(termfile);
- if (mode == 0)
- return;
- if (mode == 1) {
- (void) setenv("TERM", "wmvirt");
- (void) setenv("TERMCAP", termfile);
- }
- s = termcap(w);
- oldmask = umask(0);
- fd = creat(termfile, 0644);
- (void) umask(oldmask);
- if (fd >= 0 && write(fd, s, strlen(s)) == strlen(s)
- && write(fd, "\n", 1) == 1
- && close(fd) == 0)
- return;
- if (fd >= 0)
- (void) close(fd);
- if (mode == 1) {
- (void) setenv("TERMCAP", s);
- return;
- }
- /* gotta do it the ugly way ... */
- }
- #endif
-
- if (mode == 0)
- return;
-
- /* As suggested by Dave Eckhardt (psuvax1!dae), we check for
- * shellnames *ending* with csh as a clue that a csh is runnning.
- * (This check is also made by the SUSPEND command.)
- */
- if ((i = strlen(shellname)) >= 3
- && strcmp(shellname+i-3,"csh") == 0)
- s = "\nsetenv TERM wmvirt; setenv TERMCAP '";
- else
- s = "\nexport TERM TERMCAP; TERM=wmvirt; TERMCAP='";
-
- fd = win[w].pty;
- (void) write(fd, s, strlen(s));
-
-
- s = termcap(w);
- /* This crazy loop attempts to shield special chars from the tty driver,
- * and to fold the lines to avoid bumping into TTYHOG.
- * A TTYHOG of 255 is much too small, but lots of systems have that. */
- lasts = s;
- for (i = 0; s[i]; i++) {
- if (s[i] == killchar() || s[i] == erasechar()) {
- if (i)
- (void) write(fd, s, i);
- (void) write(fd, "\\", 1);
- s += i;
- i = 0;
- }
- else if (s[i] == ':' && i+(s-lasts) > 180 && i > 0 && s[i-1] != '\\') {
- (void) write(fd, s, i+1);
- (void) write(fd, "\\\r:", 3);
- s += i+1;
- lasts = s;
- i = 0;
- }
- }
- (void) write(fd, s, strlen(s));
-
- (void) write(fd, "'\n", 2);
- }
-
- /*
- * Find the largest unobscured rectangle on the screen,
- * returning its description as (lines, cols, begline, begcol)
- * via reference parameters.
- * The window being fitted is 'w'.
- * Returns -1 if no unobscured rectangle is found.
- *
- * Note: this algorithm is based on one from Jon Bentley's
- * "Programming Pearls" column in the CACM. Many readers
- * independently discovered the algorithm, including some
- * who wrote to Bentley and got mentioned in his column (sigh).
- * An interesting question is, is there a faster algorithm?
- * (Faster in the worst case, that is.)
- */
- fitwindow(w, lp, cp, blp, bcp)
- int w, *lp, *cp, *blp, *bcp;
- {
- short *wbase; /* vaguely like a WINDOW pointer */
- register short *wptop, *wpbot; /* Ye Olde manual code optimization */
- register int x, ytop, ybot;
- int bestarea, bestsofar, besttohere, bestx;
-
- /* Allocate an appropriately sized array */
- if (LINES > 32000
- || (wbase = alloc(LINES*COLS, short)) == NULL)
- return(-1);
-
- /* Compute cumulative coverage table in LINES*COLS steps */
- /* This is probably the slower loop, due to the subroutine call */
- for (x = 0; x < COLS; x++)
- for (ytop=0,wptop=wbase+x; ytop < LINES-1; ytop++,wptop+=COLS)
- wptop[0] = covers(w, ytop, x) + ((ytop > 0)? wptop[-COLS]: 0);
-
- /* Find largest rectangle in LINES*LINES/2*COLS steps */
- bestarea = 0;
- for (ytop = 0; ytop < LINES-1; ytop++) {
- for (ybot = ytop; ybot < LINES-1; ybot++) {
- /* Find largest rectangle in this strip */
- bestsofar = besttohere = 0;
- wptop = wbase + (ytop-1)*COLS;
- for (x=0,wpbot=wbase+ybot*COLS; x < COLS; x++,wpbot++,wptop++) {
- if (wpbot[0] - ((ytop > 0)? wptop[0]: 0))
- besttohere = 0;
- else if (++besttohere > bestsofar) {
- bestsofar = besttohere;
- bestx = x+1 - bestsofar;
- }
- }
- if (bestsofar*(ybot+1-ytop) > bestarea) {
- bestarea = bestsofar*(ybot+1-ytop);
- *lp = ybot+1-ytop;
- *cp = bestsofar;
- *blp = ytop;
- *bcp = bestx;
- }
- }
- }
- free((char *)wbase);
-
- if (bestarea <= 0)
- return(-1);
- return(0);
- }
-
- /*
- * Returns "" if n == 1, otherwise "s".
- * Useful for printing messages such as "1 line" or "2 lines".
- */
- char *
- plural(n)
- int n;
- {
- return (n == 1? "": "s");
- }
-
- /*
- * This routine is equivalent to 'malloc',
- * but returns a 'double *' which makes lint happier.
- * If only malloc were declared this way in the lint library
- * this kludge would be unnecessary.
- */
- double *
- Malloc(n)
- unsigned int n;
- {
- extern char *malloc(); /* The tyranny of the lint library */
- return((double *)malloc(n)); /* Ignore lint warning */
- }
- SHAR_EOF
- if test 11326 -ne "`wc -c < 'misc.c'`"
- then
- echo shar: error transmitting "'misc.c'" '(should have been 11326 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'save.c'" '(4419 characters)'
- if test -f 'save.c'
- then
- echo shar: will not over-write existing file "'save.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'save.c'
- /*
- *************
- * DISTRIBUTION NOTICE July 30 1985
- * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
- * Research Triangle Institute, (919) 541-7005.
- * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
- * Naval Research Laboratory, (202) 767-3365.
- * No claims or warranties of any sort are made for this distribution.
- * General permission is granted to copy, but not for profit,
- * any of this distribution, provided that this notice
- * is always included in the copies.
- *************
- */
- /*
- * save.c M. Lennon 2/07/85
- * Save and restore windows between WM sessions.
- */
-
- #include "wm.h"
-
-
- /* Save windows from this session in HOME/.wmrc.
- *
- * Produces an ascii file containing info
- * necessary for restoring windows in next WM session.
- */
- XSave(file)
-
- char *file; /* name of save file */
- {
- register FILE *fp; /* save file pointer */
- register WINDOW *w;
- register int i;
-
-
- if (*file == '\0')
- return(FALSE);
- if ((fp=fopen(file,"w")) == NULL)
- return(FALSE);
-
- fprintf(fp, "%s\n", mkprint(prefix));
-
- for (i=botw; i>=0; i=win[i].next)
- {
- w = win[i].wptr;
- fprintf(fp, "%d %d %d %d %d\n",
- i,
- (win[i].flags&YFLEX)? 0: wlines(w),
- (win[i].flags&XFLEX)? 0: wcols(w),
- wbegy(w), wbegx(w));
- }
-
- (void)fclose(fp);
- return(TRUE);
- }
-
- /*
- * Restore windows from previous session
- * as stored in ~/.wmrc.
- * Returns number of windows restored (0 on error).
- */
- Restore(file)
-
- char *file; /* name of restore file */
- {
- register FILE *fp; /* restore file pointer */
- int w; /* window index */
- int lines, cols, begline, begcol; /* window parameters */
- int count; /* number of windows restored */
- int lshrink, cshrink; /* amount that windows must be shrunk to fit */
- int rc; /* temporary to hold return code from fscanf */
- char ccbuf[10], tbuf[100]; /* temporary buffers */
- register char *p; /* temp pointer into tbuf */
-
-
- /* Open save/restore file.
- */
- if (*file == '\0')
- return(0);
- if ((fp=fopen(file,"r")) == NULL) {
- showmsg("\007Cannot read '%s'.", file);
- sleep(2);
- return(0);
- }
-
- /* Read first line of ~/.wmrc to get the WM prefix character.
- */
- if (fscanf(fp,"%2s%1[\n]", ccbuf, tbuf) != 2) {
- (void)fclose(fp);
- showmsg("\007Bad .wmrc file '%s'.", file);
- sleep(2);
- return(0);
- }
- if (ccbuf[0]=='^' && ccbuf[1])
- prefix = (ccbuf[1]=='?' ? '\177' : ccbuf[1]-0100);
- else prefix = ccbuf[0];
-
-
- /* Restore the windows.
- * Stop trying if input error encountered.
- */
- count = 0;
- for (;;)
- {
- /* Read window parameters.
- * Check for end of file, format error,
- * bad window name, and bad window dimensions.
- */
- rc = fscanf(fp,"%d%d%d%d%d%1[\n]",
- &w,&lines,&cols,&begline,&begcol,tbuf);
- if (rc == EOF)
- break;
- if (rc != 6 || lines < 0 || cols < 0 || begline < 0 || begcol < 0
- || w < MINWINDOW || w >= MAXWINDOWS || (win[w].flags&INUSE)) {
- showmsg("\007Bad window entry, file '%s'.", file);
- sleep(2);
- break;
- }
-
- /*
- * check for "flex" windows
- */
- if (lines == 0 && begline == 0) {
- lines = LINES-1;
- win[w].flags |= YFLEX;
- }
- if (cols == 0 && begcol == 0) {
- cols = COLS;
- win[w].flags |= XFLEX;
- }
-
- /* Check for windows which are beyond this screen */
- /* Bug: if .wmrc is updated these windows are omitted! */
- if (begline >= LINES-1 || begcol >= COLS) {
- showmsg("\007Window #%d is off this screen.", w);
- sleep(2);
- continue;
- }
-
- /* Check for windows which must be shrunk to fit */
- /* Bug(?): if .wmrc is updated the new sizes are saved */
- lshrink = cshrink = 0;
- if (begline+lines > LINES-1) {
- lshrink = begline+lines-(LINES-1);
- lines -= lshrink;
- }
- if (begcol+cols > COLS) {
- cshrink = begcol+cols-COLS;
- cols -= cshrink;
- }
- if (lshrink+cshrink) {
- p = tbuf;
- (void)sprintf(p, "\007Window #%d shrunk by", w); p += strlen(p);
- if (lshrink) {
- (void)sprintf(p, " %d line%s%s", lshrink, plural(lshrink),
- cshrink? " and": "");
- p += strlen(p);
- }
- if (cshrink) {
- (void)sprintf(p, " %d column%s", cshrink, plural(cshrink));
- p += strlen(p);
- }
- (void)sprintf(p, ".");
- showmsg("%s", tbuf);
- sleep(2);
- }
-
- /* Construct new window.
- */
- if (NewWindow(w,lines,cols,begline,begcol))
- continue; /* cannot happen? */
- WListAdd(w);
- count++;
- }
-
- (void)fclose(fp);
- return(count);
- }
- SHAR_EOF
- if test 4419 -ne "`wc -c < 'save.c'`"
- then
- echo shar: error transmitting "'save.c'" '(should have been 4419 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'shell.c'" '(7153 characters)'
- if test -f 'shell.c'
- then
- echo shar: will not over-write existing file "'shell.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'shell.c'
- /*
- *************
- * DISTRIBUTION NOTICE July 30 1985
- * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
- * Research Triangle Institute, (919) 541-7005.
- * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
- * Naval Research Laboratory, (202) 767-3365.
- * No claims or warranties of any sort are made for this distribution.
- * General permission is granted to copy, but not for profit,
- * any of this distribution, provided that this notice
- * is always included in the copies.
- *************
- */
- /*
- * This file contains routines dealing
- * with the window shells.
- */
-
- #include "wm.h"
- #include <signal.h>
- #include <errno.h>
-
- static struct sgttyb sgttybuf;
- static struct tchars tcharsbuf;
- static struct ltchars ltcharsbuf;
- static int ttymode;
- static int ttydisc;
- static int ttyfd; /* file descriptor for /dev/tty */
-
-
- /*
- * Initialize parameters needed for creating new window shells.
- */
- XShellInit()
- {
- (void) ioctl(0, (int)TIOCGETD, (char*)&ttydisc);
- (void) ioctl(0, (int)TIOCGETC, (char*)&tcharsbuf);
- (void) ioctl(0, (int)TIOCLGET, (char*)&ttymode);
- (void) ioctl(0, (int)TIOCGLTC, (char*)<charsbuf);
- (void) ioctl(0, (int)TIOCGETP, (char*)&sgttybuf);
-
- /*
- * The psuedo-tty driver should probably not produce
- * internal magic delay characters (cf. sys/tty.c (ttyoutput)).
- * It seems easiest to turn off all delays here.
- * (Even that is not all that easy, due to an XTABS glitch.)
- */
- {
- register int i = ALLDELAY;
- if ((sgttybuf.sg_flags&TBDELAY) == XTABS)
- i &= ~TBDELAY;
- sgttybuf.sg_flags &= ~i;
- }
-
- /* We will use 'ttyfd' later when setting
- * controlling terminals for new shells.
- */
- ttyfd = open("/dev/tty", 0);
-
- strcpy(shellpgm, getenv("SHELL") ? getenv("SHELL") : "sh");
- strcpy(shellname, rindex(shellpgm,'/') ? rindex(shellpgm,'/')+1 : shellpgm);
- }
-
- /*
- * spawn shell process for window number w
- * Finds first available pty and its matching pts and opens them
- * Returns TRUE if it found you some pty's else FALSE
- */
- NewShell(w)
-
- register int w;
- {
- static char ptlist[] = "0123456789abcdef";
- char ptyname[100], ptsname[100]; /* names of pty master/slave devices */
- int fpty, fpts; /* descriptors for "" "" "" */
- register int c, i; /* index */
- int ptydisc;
- extern int errno;
-
-
- /* Look for available pty master/slave pair.
- */
- for (c = 'p';; c++) {
- for (i = 0; ptlist[i]; i++) {
- (void) sprintf(ptyname, "/dev/pty%c%c", c, ptlist[i]);
- if ((fpty = open(ptyname, 2)) < 0) {
- if (errno == ENOENT)
- return(-1);
- continue;
- }
- (void) sprintf(ptsname, "/dev/tty%c%c", c, ptlist[i]);
- if ((fpts = open(ptsname, 2)) < 0) {
- (void) close(fpty);
- continue;
- }
- /* This doesn't close the security hole,
- * but it helps avoid certain problems.
- */
- if (ioctl(fpts, (int)TIOCGETD, (char *)&ptydisc) || ptydisc) {
- (void) close(fpts);
- (void) close(fpty);
- continue;
- }
- /* Okay, this one will do */
- goto gottatty;
- }
- }
- gottatty:;
- (void) ioctl(fpty, (int)FIOCLEX, (char *)0);
-
-
-
- /* Fork a new shell.
- */
- switch (win[w].pid=fork())
- {
- default: /* parent */
- (void) close(fpts);
- win[w].pty=fpty;
- break;
-
- case 0: /* child */
- /* Set up stdin, stdout, stderr streams. */
- dup2(fpts,0); dup2(fpts,1); dup2(fpts,2);
- if (fpts > 2)
- (void) close(fpts);
- /* Set up slave as new controlling terminal. */
- SetCntrlTerm(ptsname);
- /* Set up process groups. */
- SetProcGrp();
- /* Set pty terminal attributes. */
- InitPseudoTty();
- /* Set env variables TERM & TERMCAP. */
- #ifdef SNEAKYTERMCAP
- SetTerm(w, 1);
- #else
- (void) setenv("TERM", "wmvirt");
- (void) setenv("TERMCAP", termcap(w));
- #endif
- /* Exec the shell. */
- execlp(shellpgm, shellname, (char *)0);
- exit(1); /* exec failed */
- break;
-
- case -1: /* fork failed */
- (void) close(fpty);
- (void) close(fpts);
- break;
- }
-
- return(win[w].pid < 0);
- }
-
- /*
- * Set up terminal attributes for new pseudo-tty.
- * The attributes are those of user's regular terminal.
- * This way, the pseudo-tty will behave just like user's terminal.
- */
- InitPseudoTty()
- {
- /* Set tty discipline, edit characters,
- * mode, etc.
- */
- (void) ioctl(0, (int)TIOCSETP, (char*)&sgttybuf);
- (void) ioctl(0, (int)TIOCSETD, (char*)&ttydisc);
- (void) ioctl(0, (int)TIOCSETC, (char*)&tcharsbuf);
- (void) ioctl(0, (int)TIOCLSET, (char*)&ttymode);
- (void) ioctl(0, (int)TIOCSLTC, (char*)<charsbuf);
- }
-
- /*
- * Make 'cterm' the new controlling terminal for
- * this process. Use TIOCNOTTY to turn off
- * current control terminal. Then when we open
- * 'cterm', it automatically becomes the new
- * controlling terminal.
- * Can you say 'kludge'? I knew you could.
- */
- XSetCntrlTerm(cterm)
-
- char *cterm;
- {
- /* We really ought to check the return values
- * of these calls. Oh, well.
- */
- (void) ioctl(ttyfd, (int)TIOCNOTTY, (char*)0);
- (void) close(ttyfd);
- ttyfd = open(cterm, 0);
- (void) close(ttyfd);
- }
-
- /*
- * Set up a new process group for a process.
- * Process group id will be the pid of the current process.
- * Also set up terminal process group for the benefit of
- * csh job control facilities.
- */
- XSetProcGrp()
- {
- int pgrp;
-
- pgrp = getpid();
- (void) setpgrp(0, pgrp);
- (void) ioctl(0, (int)TIOCSPGRP, (char*)&pgrp);
- }
-
- /*
- * Kill shell (process group) in window 'w'.
- */
- KillShell(w)
-
- register int w;
- {
- if (win[w].pid <= 0)
- return;
-
- /* Close pty file.
- */
- (void) close(win[w].pty);
-
- /* Send SIGHUP to all process associated
- * with window w.
- */
- (void) kill(win[w].pid, SIGHUP);
-
- #ifdef SNEAKYTERMCAP
- SetTerm(w, 0);
- #endif
- win[w].pid = 0;
- }
-
- setenv(name, val)
-
- char *name, *val;
- {
- register int n, i;
- register char **ep, *oldval;
- char *namecmp();
- extern char **environ;
-
-
- ep = environ;
-
- /* See if the environment variable is already set.
- */
- for (n=0; ep[n]!=NULL; n++)
- if ((oldval=namecmp(name,ep[n])) != NULL)
- break;
-
- /* If the environment variable is already set and
- * the new value is no longer than the old one,
- * we can just overwrite the old one.
- */
- if (ep[n] != NULL && strlen(oldval) >= strlen(val))
- strcpy(oldval, val);
-
- /* Else we have to reallocate (name=value).
- */
- else
- {
- /* If environment variable not already set,
- * we have to reallocate entire 'environ' array
- * with one additional slot in order to add the new variable.
- * Make sure to terminate array with a NULL entry.
- */
- if (ep[n] == NULL)
- {
- if ((ep=alloc(n+2, char*)) == NULL)
- return(-1);
-
- for (i=0; i<n; i++)
- ep[i] = environ[i];
-
- ep[n+1] = NULL;
-
- environ = ep;
- }
-
- /* Allocate space for new variable, add it to 'environ'.
- */
- if ((ep[n]=alloc(strlen(name)+strlen(val)+2, char)) == NULL)
- return(-1);
- (void) sprintf(ep[n], "%s=%s", name, val);
- }
-
- return(0);
- }
-
- static char *namecmp(s1, s2)
-
- register char *s1, *s2;
- {
- for ( ; *s1==*s2; s1++,s2++)
- ;
-
- if (*s1 == '\0' && *s2 == '=')
- return(s2+1);
-
- return(NULL);
- }
- SHAR_EOF
- if test 7153 -ne "`wc -c < 'shell.c'`"
- then
- echo shar: error transmitting "'shell.c'" '(should have been 7153 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'vterm.c'" '(11456 characters)'
- if test -f 'vterm.c'
- then
- echo shar: will not over-write existing file "'vterm.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'vterm.c'
- /*
- *************
- * DISTRIBUTION NOTICE July 30 1985
- * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
- * Research Triangle Institute, (919) 541-7005.
- * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
- * Naval Research Laboratory, (202) 767-3365.
- * No claims or warranties of any sort are made for this distribution.
- * General permission is granted to copy, but not for profit,
- * any of this distribution, provided that this notice
- * is always included in the copies.
- *************
- */
- /*
- * This file contains routines for low-level virtual
- * terminal emulation.
- */
-
- #include "wm.h"
-
- #define FULLWIDTH(wp) (wcols(wp)==COLS)
- #define FULLSCREEN(wp) (FULLWIDTH(wp) && wlines(wp)==LINES-1)
-
- /* Termcap entry for virtual terminals.
- */
- static char TERMCAP[]="wm|wmvirt|wm virtual terminal:am:bs:ce=\\EK:ho=\\EH:cd=\\EB:cl=\\ES:nd=\\EC:up=\\EA:cm=\\EY%+ %+ :";
- #define TBUFLEN (sizeof(TERMCAP)+300) /* max length of termcap string */
-
- extern char *tgoto(), *tparm();
-
- /*
- * Add 'n' characters of 'p' to window 'w' at its current (y, x) coordinate.
- */
- WMaddbuf(w, p, n)
- int w;
- register char *p;
- register int n;
- {
- register WINDOW *wp;
- register int y, x;
- register int c;
-
- /*
- * Are we in the midst of an escape sequence?
- */
- while (win[w].pend[0] && --n >= 0)
- WMescape(w, toascii(*p++));
-
- wp = win[w].wptr;
- getyx(wp, y, x);
-
-
- while (--n >= 0) switch (c = toascii(*p++))
- {
- case '\t':
- x = (x+8) & ~07;
- while (x >= wcols(wp)) {
- WMaddbuf(w, "\n", 1);
- x -= wcols(wp);
- }
- wmove(wp, y = wcury(wp), x);
- break;
- case '\n':
- if (++y >= wlines(wp)) {
- --y;
- wmove(wp, 0, x); WMdeleteln(w);
- }
- wmove(wp, y, x);
- break;
- case '\r':
- wmove(wp, y, x = 0);
- break;
- case '\b':
- if (x>0) wmove(wp, y, --x);
- break;
- case '\007':
- beep();
- break;
- case '\0':
- break;
- case ESC:
- win[w].pend[0] = ESC;
- win[w].pend[1] = '\0';
- while (win[w].pend[0] && --n >= 0)
- WMescape(w, toascii(*p++));
- getyx(wp, y, x);
- break;
- /* Dummy cases to fool pcc into generating a fast switch table */
- case 01: case 02: case 03: case 04: case 05: case 06:
- default:
- if (isprint(c))
- {
- waddch(wp, c);
- if (++x >= wcols(wp)) {
- if (++y >= wlines(wp)) {
- --y;
- wmove(wp, 0, 0); WMdeleteln(w);
- }
- wmove(wp, y, x = 0);
- }
- }
- else
- {
- char *s = mkprint(c);
- WMaddbuf(w, s, strlen(s));
- getyx(wp, y, x);
- }
- break;
- }
- }
-
- /*
- * Construct virtual terminal escape sequence
- * one character at a time.
- * When escape sequence is complete, perform
- * the indicated action in window 'w'.
- */
- WMescape(w, c)
- int w;
- int c;
- {
- register WINDOW *wp;
- register int y, x;
- register char *pend;
- int oldx, oldy;
-
-
- pend = win[w].pend;
- wp = win[w].wptr;
- getyx(wp, y, x);
-
- /* ESC-Y is a multi-character escape sequence
- * so we need to make sure we have all the
- * characters before we start processing it.
- */
- if (c == 'Y' && pend[1] == '\0') { pend[1]=c; pend[2]='\0'; return; }
-
- else if (pend[1] == 'Y')
- {
- if (pend[2]=='\0') { pend[2]=c; return; }
- else { pend[3]=c; c='Y'; }
- }
-
- /* Process escape sequence.
- */
- pend[0] = '\0'; /* escape no longer pending */
- switch (c)
- {
- case 'Y': /* cursor motion */
- y = oldy = pend[2]-' '; x = oldx = pend[3]-' ';
- if (x < 0) x = 0;
- if (y < 0) y = 0;
- if (x >= wcols(wp)) x = wcols(wp)-1;
- if (y >= wlines(wp)) y = wlines(wp)-1;
- if (y != oldy || x != oldx)
- showmsg("Bad cursor motion to (%d,%d).", oldy, oldx);
- wmove(wp, y, x);
- break;
- case 'K': /* clear to end of line */
- wclrtoeol(wp);
- break;
- case 'B': /* clear to bottom of window */
- wclrtobot(wp);
- break;
- case 'H': /* home cursor */
- wmove(wp, 0, 0);
- break;
- case 'R': /* visual bell */
- flash();
- break;
- case 'D': /* delete line */
- WMdeleteln(w);
- break;
- case 'L': /* insert line */
- WMinsertln(w);
- break;
- case 'P': /* insert character */
- #ifdef CURSEASSIST
- #ifndef TERMINFO
- if (FULLWIDTH(wp) && insert_character && !insert_null_glitch) {
- (void) movecursor(wbegy(wp)+y, wbegx(wp)+x);
- putp(insert_character); winsch(curscr, ' ');
- }
- #endif
- #endif
- winsch(wp, ' ');
- break;
- case 'Q': /* delete character */
- #ifdef CURSEASSIST
- #ifndef TERMINFO
- if (FULLWIDTH(wp) && delete_character) {
- (void) movecursor(wbegy(wp)+y, wbegx(wp)+x);
- putp(delete_character); wdelch(curscr);
- }
- #endif
- #endif
- wdelch(wp);
- break;
- case 'S': /* erase window */
- werase(wp);
- #ifdef CURSEASSIST
- if (FULLSCREEN(wp) && !msgbirth)
- clearok(curscr, TRUE);
- #endif
- break;
- case 'C': /* non-destructive blank */
- if (++x >= wcols(wp)) {
- WMaddbuf(w, "\n", 1);
- x = 0;
- }
- wmove(wp, wcury(wp), x);
- break;
- case 'A': /* cursor up */
- if (--y>=0) wmove(wp, y, x);
- break;
- case 'O': /* enter standout mode */
- wstandout(wp);
- break;
- case 'E': /* leave standout mode */
- wstandend(wp);
- break;
- default:
- {
- char *s;
- s = mkprint(ESC);
- WMaddbuf(w, s, strlen(s));
- s = mkprint(c);
- WMaddbuf(w, s, strlen(s));
- }
- break;
- }
- }
-
- /*
- * Insert a line just above the current line of window wp.
- * The cursor location in wp is not changed.
- */
- WMinsertln(w)
- int w;
- {
- register WINDOW *wp;
- register int curline, curcol;
-
- wp = win[w].wptr;
- wrefresh(wp); /* smooths scrolling. Crucial for untouchwin. */
- winsertln(wp);
-
- #ifdef CURSEASSIST
- /* If this terminal has scrolling regions, use them */
- if (has_scroll_region && FULLWIDTH(wp)) {
- /* First, get curscr management out of the way. */
- curline = cursrow(); curcol = curscol();
- Cmove(wbegy(wp)+wlines(wp)-1, 0);
- Cdeleteln();
- Cmove(wbegy(wp)+wcury(wp), 0);
- Cinsertln();
- Cmove(curline, curcol);
- /* now update the screen itself */
- (void) movecursor(wbegy(wp)+wcury(wp), wbegx(wp)+wcurx(wp));
- putp(save_cursor); /* Save since CS garbles cursor */
- putp(tgoto(change_scroll_region,
- wbegy(wp)+wlines(wp)-1, wbegy(wp)+wcury(wp)));
- putp(restore_cursor); /* CS garbles cursor */
- putp(scroll_reverse);
- putp(tgoto(change_scroll_region, LINES-1, 0));
- putp(restore_cursor); /* Once again put it back */
- Untouchwin(wp);
- }
-
- /* Else if this terminal has scrolling rectangles, use them now. */
- #ifdef SET_WINDOW
- else if (has_scroll_window) {
- overwrite(wp, curscr); /* slow but easy */
- putp(tparm(set_window,
- wbegy(wp)+wcury(wp), wbegy(wp)+wlines(wp)-1,
- wbegx(wp), wbegx(wp)+wcols(wp)-1));
- putp(scroll_reverse);
- putp(tparm(set_window, 0, LINES-1, 0, COLS-1));
- /* get back to where curses thinks we are */
- putp(tgoto(cursor_address, curscol(), cursrow()));
- Untouchwin(wp);
- }
- #endif
-
- /* Else if this terminal has ins/del line, now is the time */
- else if (has_insdel_line && FULLWIDTH(wp)) {
- /* Open a line above current line in window wp,
- * then delete wp's bottom line.
- * Perform identical operations on curscr
- * as we do on the terminal itself.
- */
- (void) movecursor(wbegy(wp)+wcury(wp), 0);
- putp(insert_line); Cinsertln();
- (void) movecursor(wbegy(wp)+wlines(wp), 0);
- putp(delete_line); Cdeleteln();
- RestoreMsg();
- Untouchwin(wp);
- }
- #endif
- }
-
- /*
- * This routine deletes the current line in window wp.
- * The cursor location in wp is not changed.
- */
- WMdeleteln(w)
- int w;
- {
- register WINDOW *wp;
- register int curline, curcol;
-
- wp = win[w].wptr;
-
- /*
- * See what we can do about windows that scroll slowly
- */
- if (!(win[w].flags&FAST)) {
- static int lines_since_refresh = 0;
- if ((lines_since_refresh += 7) >= wlines(wp)) {
- wrefresh(wp);
- lines_since_refresh = 0;
- }
- wdeleteln(wp);
- #ifdef BUGGYTERMINFO
- touchwin(wp);
- #endif
- return;
- }
-
- wrefresh(wp); /* smooths scrolling. Crucial for untouchwin. */
- wdeleteln(wp);
- #ifdef BUGGYTERMINFO
- /* wdeleteln neglects first/bottom info for the last line */
- touchwin(wp);
- #endif
-
- #ifdef CURSEASSIST
- /* If we're deleting top line of a full screen window,
- * this is the same as scrolling.
- * (We do not this if we have scrolling region support
- * and there is a wm message, but what a bother.)
- */
- if (FULLSCREEN(wp) && wcury(wp)==0 && !(has_scroll_region && msgbirth))
- {
- ZapMsgLine(); /* so it doesn't scroll up into our window */
- curline = cursrow(); curcol = curscol();
- Cmove(0, 0); Cdeleteln();
- Cmove(curline, curcol);
-
- /* Cause screen to scroll.
- * Since wm almost always 'wants' the cursor on LINES-2,
- * there is a cheap heuristic thrown in.
- */
- (void) movecursor(LINES, curcol);
- #ifndef TERMINFO
- if (cursor_up) {
- putp(cursor_up);
- Cmove(LINES-2, curcol);
- }
- #endif
- RestoreMsg();
- Untouchwin(wp);
- }
-
- /* Else if this terminal has scrolling regions, use them. */
- else if (has_scroll_region && FULLWIDTH(wp)) {
- curline = cursrow(); curcol = curscol();
- Cmove(wbegy(wp)+wcury(wp), 0);
- Cdeleteln(); /* it is about to be deleted */
- Cmove(wbegy(wp)+wlines(wp)-1, 0);
- Cinsertln(); /* it is about to be cleared */
- Cmove(curline, curcol);
- (void) movecursor(wbegy(wp)+wlines(wp)-1, wbegx(wp)+wcurx(wp));
- putp(save_cursor); /* Save since CS garbles cursor */
- putp(tgoto(change_scroll_region,
- wbegy(wp)+wlines(wp)-1, wbegy(wp)+wcury(wp)));
- putp(restore_cursor); /* put cursor back */
- putp(scroll_forward);
- putp(tgoto(change_scroll_region, LINES-1, 0));
- putp(restore_cursor); /* put cursor back */
- Untouchwin(wp);
- }
-
- /* Else if this terminal has scrolling rectangles, use them. */
- #ifdef SET_WINDOW
- else if (has_scroll_window) {
- overwrite(wp, curscr); /* slow but easy */
- putp(tparm(set_window,
- wbegy(wp)+wcury(wp), wbegy(wp)+wlines(wp)-1,
- wbegx(wp), wbegx(wp)+wcols(wp)-1));
- putp(tgoto(cursor_address, 0, wlines(wp)-1));
- putp(scroll_forward);
- putp(tparm(set_window, 0, LINES-1, 0, COLS-1));
- putp(tgoto(cursor_address, curscol(), cursrow()));
- Untouchwin(wp);
- }
- #endif
-
- /* Else if this terminal has insdel line, use that. */
- else if (has_insdel_line && FULLWIDTH(wp)) {
- /* Open a line below the last line in window wp,
- * then delete wp's current line.
- */
- (void) movecursor(wbegy(wp)+wlines(wp), 0);
- putp(insert_line); Cinsertln();
- (void) movecursor(wbegy(wp)+wcury(wp), 0);
- putp(delete_line); Cdeleteln();
- RestoreMsg();
- Untouchwin(wp);
- }
- #endif
- }
-
- /*
- * Construct termcap for wmvirt terminal in window w.
- */
- char *
- termcap(w)
- int w;
- {
- register WINDOW *wp;
- static char tbuf[TBUFLEN]; /* termcap buffer */
-
- wp = win[w].wptr;
- (void)sprintf(tbuf, "%sco#%d:li#%d:", TERMCAP, wcols(wp), wlines(wp));
-
- /* If terminal scrolls 'quickly', add insert/delete line to termcap. */
- if ((win[w].flags&FAST)
- && (has_insdel_line || has_scroll_region || has_scroll_window))
- strcat(tbuf, "al=\\EL:dl=\\ED:");
-
- /* If terminal has insert/delete character options, add them here */
- if (insert_character || (enter_insert_mode && exit_insert_mode))
- strcat(tbuf, "ic=\\EP:");
- if (delete_character)
- strcat(tbuf, "dc=\\EQ:");
-
- /* If terminal has standout capabilities, add that too. */
- if (enter_standout_mode && exit_standout_mode)
- strcat(tbuf, "so=\\EO:se=\\EE:");
-
- /* Include vb if terminal has a visual bell */
- if (flash_screen)
- strcat(tbuf, "vb=\\ER:");
-
- /* Include keypad capabilities if there is room left */
- if (strlen(tbuf)+strlen(keycap) < TBUFLEN)
- strcat(tbuf, keycap);
-
- return(tbuf);
- }
- SHAR_EOF
- if test 11456 -ne "`wc -c < 'vterm.c'`"
- then
- echo shar: error transmitting "'vterm.c'" '(should have been 11456 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'wlist.c'" '(3611 characters)'
- if test -f 'wlist.c'
- then
- echo shar: will not over-write existing file "'wlist.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'wlist.c'
- /*
- *************
- * DISTRIBUTION NOTICE July 30 1985
- * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
- * Research Triangle Institute, (919) 541-7005.
- * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
- * Naval Research Laboratory, (202) 767-3365.
- * No claims or warranties of any sort are made for this distribution.
- * General permission is granted to copy, but not for profit,
- * any of this distribution, provided that this notice
- * is always included in the copies.
- *************
- */
- /*
- * Code for rearranging window display order
- */
-
- #include "wm.h"
-
-
- /*
- * Make window 'w' the new top window.
- * Insert 'w' into window list (keeps track
- * of redraw order).
- * 'topw' (pointer to the top window) is set to 'w'.
- * Recompute obscured window status.
- */
- WListAdd(w)
-
- register int w;
- {
- register int wt; /* temporary window pointer */
-
- /* Add w to empty list.
- */
- if (botw < 0)
- botw=w;
-
- /* Add w to top of nonempty list.
- */
- else
- {
- for (wt=botw; win[wt].next>=0; wt=win[wt].next)
- ;
- win[wt].next=w;
- }
-
-
- win[w].next = -1;
- topw = w;
-
- /* Recompute obscured window status */
- WObscure();
- }
-
- /*
- * Delete window 'w'.
- * Remove it from window list.
- * Recompute obscured windows.
- */
- WListDelete(w)
-
- register int w;
- {
- register int wt; /* temporary window pointer */
-
- if ( ! iswindow(w))
- return;
-
- /* Don't read from this window any more.
- */
- DisablePty(w);
-
- /* Delete w from list.
- */
- if (botw==w)
- botw=win[botw].next;
- else
- {
- for (wt=botw; wt>=0; wt=win[wt].next)
- if (win[wt].next==w) break;
- if (wt>=0)
- win[wt].next=win[win[wt].next].next;
- }
-
- /* Find new topw.
- */
- wt=botw;
- while (wt>=0 && win[wt].next>=0)
- wt=win[wt].next;
- topw=wt;
-
- /* Recompute obscured window info */
- WObscure();
- }
-
- /*
- * Recompute obscured ('blocked') and 'covers' information
- * Enable/Disable ptys appropriately.
- */
- WObscure()
- {
- register int w, wt, i;
-
- for (w = botw; w >= 0; w = win[w].next) {
- EnablePty(w);
- win[w].flags &= ~BLOCKED;
- for (i = 0; i < MAXWINDOWS; i++)
- win[w].covers[i] = FALSE;
- for (wt = botw; wt != w; wt = win[wt].next) {
- if (!overlap(w, wt))
- continue;
- win[w].covers[wt] = TRUE;
- win[wt].flags |= BLOCKED;
- /* We could disable the obscured window's pty at this point,
- * but we'll wait and do it in 'readptys()'.
- */
- /* (we should probably disable it now if it was previously) */
- }
- }
- }
-
- /* Note: the arithmetic 'bottom' is actual the visual 'top'!
- * Also, RIGHT and TOP are the index of the column (row) just past
- * the index of the window's actual right (top).
- */
- #define BOTTOM(wp) (wbegy(wp))
- #define TOP(wp) (BOTTOM(wp)+wlines(wp))
- #define LEFT(wp) (wbegx(wp))
- #define RIGHT(wp) (LEFT(wp)+wcols(wp))
-
- /*
- * Determine if two windows overlap.
- * Windows must have at least a row (column) separating them
- * to permit the border lines to be drawn.
- */
- overlap(w1, w2)
-
- int w1, w2;
- {
- register WINDOW *wp1, *wp2;
-
- wp1 = win[w1].wptr;
- wp2 = win[w2].wptr;
- return(LEFT(wp1) <= RIGHT(wp2)
- && LEFT(wp2) <= RIGHT(wp1)
- && BOTTOM(wp1) <= TOP(wp2)
- && BOTTOM(wp2) <= TOP(wp1));
- }
-
- /*
- * Returns 1 if a window (or its border) above w cover point (y,x),
- * otherwise returns 0.
- */
- covers(w, y, x)
- int w;
- register int y, x;
- {
- register int wt;
- register WINDOW *wp;
-
- for (wt = w; (wt = win[wt].next) >= 0;) {
- wp = win[wt].wptr;
- if (LEFT(wp) <= x+1
- && x <= RIGHT(wp)
- && BOTTOM(wp) <= y+1
- && y <= TOP(wp))
- return(1);
- }
- return(0);
- }
- SHAR_EOF
- if test 3611 -ne "`wc -c < 'wlist.c'`"
- then
- echo shar: error transmitting "'wlist.c'" '(should have been 3611 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'wm.c'" '(12415 characters)'
- if test -f 'wm.c'
- then
- echo shar: will not over-write existing file "'wm.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'wm.c'
- /*
- *************
- * DISTRIBUTION NOTICE July 30 1985
- * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
- * Research Triangle Institute, (919) 541-7005.
- * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
- * Naval Research Laboratory, (202) 767-3365.
- * No claims or warranties of any sort are made for this distribution.
- * General permission is granted to copy, but not for profit,
- * any of this distribution, provided that this notice
- * is always included in the copies.
- *************
- */
- /*
- * wm.c R. Jacob 7/28/1980
- * Simple multiple-window monitor for Unix
- * allows windows to overlap
- *
- * This is the code for the main program
- *
- * This version runs as only one process (plus the shells)
- * This is intended for Berkeley 4.2 VAX Unix only.
- */
-
- #include "wm.h"
- #include <signal.h>
- #include <sys/wait.h>
- #include <sys/time.h>
- #include <sys/resource.h>
-
- #define LINEBUF 64 /* size of pty input buffer */
-
-
- /*
- * Real declarations for stuff defined as extern in wm.h
- */
- struct win_struct win[MAXWINDOWS]; /* array of windows */
- int botw, topw, lastw; /* bottom, top, last windows */
- int prefix = '\033'; /* prefix character */
- char savefile[100]; /* name of save/restore file */
- char shellname[20]; /* name of shell */
- char shellpgm[100]; /* pathname of shell */
- int configflag = FALSE; /* true if .wmrc config. has changed */
- #ifndef TERMINFO
- char *change_scroll_region, *save_cursor, *restore_cursor;
- char *set_window;
- #endif
- int has_scroll_window = FALSE; /* true if terminal has 'usable' set_window */
- int has_scroll_region = FALSE; /* true if terminal has 'usable' SR */
- int has_insdel_line = FALSE; /* true if terminal has both ins+del line */
-
- static int savereadmask; /* pty readmask */
- static int childdied = FALSE; /* set when a window shell stops */
- static int restorflag=TRUE; /* TRUE if we're restoring windows */
- static int MaxQueued = 150;
- static long pausetime = 200000L;
- static int clamp_down; /* number of chars to remain snappy after ctrl-S */
- static int Divisor; /* read/write reduction factor */
-
- main(argc, argv)
-
- int argc;
- char *argv[];
- {
- register int c; /* input character */
- int readmask; /* temp pty readmask */
- register int w; /* window index */
- register int quit = FALSE; /* Did user give the 'quit' command? */
- register struct timeval *tp;
- struct timeval timeout;
- register char *s;
-
-
- setbuf(stdout, alloc(BUFSIZ, char));
- DoCmdArgs(argc, argv);
-
- Startup();
-
- /* Adjust MaxQueued and pausetime values for fast terminals */
- {
- int ttyspeed;
- if ((ttyspeed = baudrate()) > 4800) {
- pausetime /= 2;
- if (ttyspeed > B9600)
- MaxQueued *= 2;
- }
- }
-
- /* Try to restore window arrangement from a previous
- * WM session. 'Restore()' returns number of windows restored.
- * If no windows restored, start from scratch,
- * providing user with a full screen window.
- */
- ClearScreen();
- if (restorflag==FALSE || Restore(savefile) <= 0)
- {
- if (savefile[0] == '\0')
- strcpy(savefile, ".wmrc");
- w = GetSlot();
- if (NewWindow(w, LINES-1, COLS, 0, 0))
- {
- showmsg("Sorry, can't create any windows.");
- FreeWindow(w);
- Shutdown(1);
- }
- WListAdd(w);
- }
- RedrawScreen();
-
- showmsg("Welcome to WM. Type %sh for help.", mkprint(prefix));
- RestoreCursor();
-
-
- /* Main processing loop.
- */
- do
- {
- if (childdied)
- ReapShell();
-
- /* If the shell in the top window has died (pid == -1),
- * or was never started to begin with (pid == 0),
- * start a new shell.
- */
- if (win[topw].pid <= 0)
- {
- if (win[topw].pid < 0)
- showmsg("\007Shell in current window died. Restarting...");
-
- if (NewShell(topw))
- {
- showmsg("\007Sorry, can't start up new shell.");
- win[topw].pid = -1;
- }
- else
- EnablePty(topw);
- RestoreCursor();
- }
-
- /* Poll user's terminal and ptys.
- */
- readmask = savereadmask;
- tp = 0;
- Divisor = (clamp_down? 4: 1);
-
- #ifdef TIOCOUTQ
- {
- long n;
- if (ioctl(1, (int)TIOCOUTQ, (char*)&n)==0 && n > MaxQueued/Divisor)
- {
- readmask &= 01;
- tp = &timeout;
- tp->tv_sec = 0;
- tp->tv_usec = pausetime/Divisor;
- }
- }
- #endif
-
- if (select(8*sizeof(readmask), &readmask, 0, 0, tp) <= 0)
- continue;
-
- /* Terminate messages after a few seconds */
- if (msgbirth && abs(time((time_t *)0) - msgbirth) > 3)
- showmsg("");
-
- /* If no input from the user, read ptys.
- */
- if ((readmask&01) == 0) {
- readptys(readmask);
- continue;
- }
-
- /* If user input is not the WM command prefix character,
- * just send input to the appropriate pty.
- */
- do {
- if ((c = tty_getch()) != prefix) {
- (void)write(win[topw].pty, tty_text, tty_textlen);
- if (c == CTRL(S))
- clamp_down = LINES*COLS/2;
- }
-
- /* Process WM command.
- */
- else
- {
- showmsg("#%d Command?", topw);
- c = tty_getch();
- showmsg("");
- if (c != prefix)
- quit = docmd(c);
- else
- (void)write(win[topw].pty, tty_text, tty_textlen);
- RestoreCursor();
- }
- } while (tty_backcnt > 0);
- } while ( ! quit);
-
-
- /* If user has changed the window configuration since
- * the session began, see if they want to save the
- * current configuration.
- */
- if (restorflag && configflag)
- {
- showmsg("Save current (modified) window configuration? [no] ");
- c = tty_getch();
- if (c != 'y' && c != 'Y')
- showmsg("");
- else if ( (s = WPrompt("save file", savefile)) == NULL)
- ;
- else if (Save(s) != 0)
- showmsg("Saved current window configuration in '%s'.", s);
- else
- showmsg("Sorry, can't save current window configuration.");
- }
-
-
- /* Shut down.
- */
- Shutdown(0);
- }
-
- static char USAGE[] = "[ -n ] [ -f savefile ]";
-
- /*
- * Interpret command line arguments to wm.
- */
- DoCmdArgs(argc, argv)
-
- register int argc; /* arg count */
- register char *argv[]; /* arg list */
- {
- for (argv++,argc--; argc>0; argv++,argc--)
- {
- if (**argv != '-')
- {
- fprintf(stderr, "usage: wm %s\n", USAGE);
- exit(1);
- }
- switch ((*argv)[1])
- {
- case 'f': /* next arg is name of save/restore file */
- strcpy(savefile, *++argv);
- argc--;
- break;
- case 'n': /* don't restore/save window configuration */
- restorflag = FALSE;
- break;
- default:
- fprintf(stderr, "wm: unknown option '%s'\n", *argv);
- fprintf(stderr, "usage: wm %s\n", USAGE);
- exit(1);
- }
- }
- }
-
- /*
- * Initialize WM.
- */
- XStartup()
- {
- register int w; /* window pointer */
- int onintr(), sigchild(); /* interrupt handler */
-
- savereadmask = 01;
- ShellInit(); /* this call must precede the suspend()! */
-
- /* Catch signals.
- * Note: there is a tiny window from here to the return of raw().
- * Signals could be ignored until then, but it is a bother.
- */
- if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
- (void)signal(SIGHUP, onintr);
- if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
- (void)signal(SIGQUIT, onintr);
- if (signal(SIGINT, SIG_IGN) != SIG_IGN)
- (void)signal(SIGINT, onintr);
- if (signal(SIGPIPE, SIG_IGN) != SIG_IGN)
- (void)signal(SIGPIPE, onintr);
- (void)signal(SIGCHLD, sigchild);
-
- /* Initialize curses stuff.
- */
- if ((w = (int)initscr()) == ERR || !cursor_address) {
- /* This ERR nonsense is for the benefit of terminfo curses.
- * Has initscr cleaned up correctly (e.g. reset the tty)?
- * I sure wish initscr always suceeded.
- */
- if (w != ERR)
- endwin();
- fprintf(stderr, "Sorry. Need cursor addressing to play WM\n");
- /* If 'wm' is run via exec from a .profile, then exiting here
- * would log the luser out. Unfortunately, we cannot reliably
- * determine if wm's parent is a shell, so we cannot
- * simply exit now.
- */
- fprintf(stderr, "Spawning a normal shell\n");
- execlp(shellpgm, shellname, (char *)0);
- exit(1);
- }
- noecho(); raw();
- leaveok(stdscr, TRUE);
-
- #ifdef TERMINFO
- #ifdef BUGGYTERMINFO
- /* buggyterminfo neglects the move_standout_mode problem */
- if (!move_standout_mode)
- set_attributes = enter_standout_mode = exit_standout_mode = NULL;
- /* in buggyterminfo, idlok leads to core dumps */
- #else
- idlok(curscr, TRUE); /* the first arg is pointless, yes? */
- #endif
- #else
- /*
- * hack to check for scrolling-region capability (vt100)
- * since curses does not itself check.
- */
- change_scroll_region = getcap("cs");
- save_cursor = getcap("sc");
- restore_cursor = getcap("rc");
- set_window = getcap("sw");
- #ifdef GAGMEKEYPAD
- init_keypad();
- #endif
- #endif
-
- /* ensure there is a 'scroll_forward' string */
- if (!scroll_forward)
- scroll_forward = "\n";
- if (change_scroll_region && save_cursor
- && restore_cursor && scroll_reverse)
- has_scroll_region = TRUE;
- if (insert_line && delete_line)
- has_insdel_line = TRUE;
- if (set_window && scroll_reverse)
- has_scroll_window = TRUE;
-
- /* Init window structure array.
- */
- topw = botw = lastw = -1;
- for (w=0; w<MAXWINDOWS; w++)
- win[w].flags = 0;
-
- /* Set up save/restore file name.
- * If there is a file '.wmrc' in the current directory,
- * use it. Otherwise use .wmrc in the user's home directory.
- */
- if (*savefile == '\0')
- {
- if (access(".wmrc",0) == 0)
- strcpy(savefile, ".wmrc");
- else if (getenv("HOME") != NULL) {
- (void)sprintf(savefile, "%s/.wmrc", getenv("HOME"));
- if (access(savefile,0) != 0)
- *savefile = '\0';
- }
- }
- }
-
- /*
- * Shut down WM and exit.
- */
- XShutdown(code)
-
- int code; /* exit code */
- {
- register int w; /* window pointer */
-
-
- /* Kill processes associated with each window.
- */
- for (w=0; w<MAXWINDOWS; w++)
- if (win[w].flags&INUSE) { KillShell(w); FreeWindow(w); }
-
- (void) movecursor(LINES-1, 0);
- endwin();
- putchar('\n');
-
- exit(code);
- }
-
- /*
- * Check each pty for input.
- * If present, read input and send it to that window.
- * The readmask from the last 'select()' call tells us
- * which pty's have input pending.
- */
- readptys(rmask)
-
- register int rmask; /* IN: read mask from last 'select()' call */
- {
- char buf[LINEBUF]; /* input buffer */
- register int w; /* window */
- #ifdef oldway
- register int i; /* index */
- #endif
- register int n; /* number of bytes pending on read */
-
-
- for (w=botw; w>=0; w=win[w].next)
- {
- if ((rmask & (01<<win[w].pty)) == 0)
- continue;
-
- /* If window is blocked, notify user that window
- * has pending output.
- */
- if (win[w].flags&BLOCKED)
- {
- DisablePty(w);
- showmsg("\007Output pending in window #%d.", w);
- continue;
- }
-
- /* Read and process output for window w.
- */
- n = read(win[w].pty, buf, LINEBUF/Divisor);
- if (n <= 0)
- continue;
- WMaddbuf(w, buf, n);
- wrefresh(win[w].wptr);
- if (clamp_down)
- if ((clamp_down -= n) < 0)
- clamp_down = 0;
- }
-
- RestoreCursor();
- }
-
- /*
- * Signal handler.
- */
- onintr(n)
- {
- (void)signal(n, SIG_IGN);
- Shutdown(1);
- }
-
- /*
- * Signal handler for SIGCHLD
- * (received whenever a window shell dies).
- */
- sigchild()
- {
- (void) signal(SIGCHLD, sigchild); /* not needed in 4.2bsd */
- childdied = TRUE;
- }
-
- /*
- * Clean up after dead window shell.
- */
- ReapShell()
- {
- register int w; /* window index */
- register int pid; /* process id of child */
- register int pgrp; /* process group of child */
- union wait status;
-
-
- /* Reset flag.
- */
- childdied = FALSE;
-
- /* Figure out which children died,
- * clean up after them.
- */
- while ((pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0)) > 0)
- {
- /* It is truly amazing how complex simple things can become */
- if (WIFSTOPPED(status)) {
- if (status.w_stopsig == SIGTTOU || status.w_stopsig == SIGTTIN)
- continue; /* Let's not worry about these */
- showmsg("Cannot suspend a window shell.");
- RestoreCursor();
- if ((pgrp = getpgrp(pid)) <= 0 || killpg(pgrp, SIGCONT))
- (void) kill(pid, SIGCONT); /* so there! */
- continue;
- }
- for (w=botw; w>=0; w=win[w].next)
- if (win[w].pid == pid)
- {
- DisablePty(w);
- KillShell(w);
- win[w].pid = -1;
- break; /* out of for loop */
- }
- }
- }
-
- /*
- * Enable pty of window w for reading.
- */
- EnablePty(w)
-
- register int w; /* window whose pty we're enabling */
- {
- if (win[w].pid > 0)
- savereadmask |= (01 << win[w].pty);
- }
-
- /*
- * Disable pty of window w for reading.
- */
- DisablePty(w)
-
- register int w; /* window whose pty we're disabling */
- {
- if (win[w].pid > 0)
- savereadmask &= ~(01 << win[w].pty);
- }
- SHAR_EOF
- if test 12415 -ne "`wc -c < 'wm.c'`"
- then
- echo shar: error transmitting "'wm.c'" '(should have been 12415 characters)'
- fi
- fi # end of overwriting check
- # End of shell archive
- exit 0
-